/**
 *
 *
 */
var SocialDashboard = new function() {

/**
 *
 */
function extend(superclass, properties) {
  var f = function() {
    superclass.apply(this, arguments);
    this.init.apply(this, arguments);
  }
  var subclass = function(){};
  subclass.prototype = superclass.prototype;
  f.prototype = new subclass;
  $.extend(f.prototype, properties);
  return f;
}

/**
 *
 *
 */
function deepCopy(obj) {
  return gadgets.json.parse(gadgets.json.stringify(obj));
}


/**
 *
 */
var Dashboard = function(config, container) { 
  this.config = config;

  this.el = $('<div class="dashboard" />')
    .appendTo(container)
    .data('dashboard', this)
    .height($(document).height())

  this.prepareScreens(config);
  this.renderScreenNav();
  this.renderProfile(config);
  this.switchToDefault(); 
  this.dirty(false);

  var dashboard = this;
  $(window).resize(function(){
    dashboard.el.height($(document).height());
  });

}

Dashboard.LABEL_SETTING_LINK = 'Setting';
Dashboard.LABEL_LOGOUT_LINK = 'Logout';

Dashboard.prototype = {
  /**
   *
   */
  renderProfile : function() {
    var dashboard = this;
    var profileEl = $('<div class="profile" />')
      .append('<div class="l"><div class="c"></div></div>')
      .append('<div class="bl"><div class="bc"></div></div>')
      .appendTo(this.el)

    if ($.anonymous) {
      $('<div class="login" />')
        .appendTo(profileEl.find('.c'))
        .signIn(function() { SocialDashboard.refresh() })
    } else {
      $.ajax({
        url : '/people/@viewer/@self',
        dataType : 'data'
      })
      .next(function(data) {
        var viewer = data[0];
        profileEl.find('.c')
         .append($('<img class="photo"/>').attr('src', viewer.thumbnailUrl))
         .append($('<span class="name" />').text(viewer.displayName))
         .append('<br />')
         .append($('<a href="#" class="setting" />')
                 .text(Dashboard.LABEL_SETTING_LINK)
                 .click(function() { dashboard.showSettingDialog() }))
         .append($('<span class="separator" />').text('|'))
         .append($('<a href="#" class="logout" />')
                 .text(Dashboard.LABEL_LOGOUT_LINK)
                 .click(function() { $.signOut(function() { SocialDashboard.refresh() }) }))
         .append('<div class="clearfix" />')
      })
    }
  }
  ,

  /**
   *
   */
  prepareScreens : function(config) {
    for (var i=0, len=config.screens.length; i<len; i++) {
      var scrconfig = config.screens[i];
      $('<div class="screen" id="screen-'+(i+1)+'"/>')
        .append(
          $('<div class="wallpaper" />').css({
            backgroundColor : scrconfig.bgcolor || 'transparent',
            backgroundImage : scrconfig.bgimage ? 'url('+scrconfig.bgimage+')' : 'none',
            opacity : typeof scrconfig.opacity == 'number' ? scrconfig.opacity : 1
          })
        )
        .hide()
        .appendTo(this.el)
    }
  }
  ,

  /**
   *
   */
  renderScreenNav : function() {
    var dashboard = this;
    dashboard.el 
      .append($('<div class="nav prev" />').html('&laquo;'))
      .append($('<div class="nav next" />').html('&raquo;'))
      .find('.nav')
        .css({
          top : Math.floor((dashboard.el.height() - 250)/2),
          opacity : .1
        })
        .mouseover(function() { 
          $(this).css('opacity', .5)
        })
        .mouseout(function() {
          $(this).css('opacity', .1)
        })
        .click(function() {
          var offset = $(this).hasClass('prev') ? -1 : 1;
          dashboard.switchTo(dashboard.targetIdx+offset);
        });
  }
  ,

  /**
   *
   */
  switchToDefault : function() {
    var locationUrl = environment.locationUrl;
    this.targetIdx = 0;
    if (locationUrl) {
      var matched;
      for (var i=0, len=this.config.screens.length; i<len; i++) {
        var scrconfig = this.config.screens[i];
        if (scrconfig.urlpattern) {
          var urlpattern = 
            '^'+scrconfig.urlpattern.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$';
          if (new RegExp(urlpattern).test(locationUrl)) {
            matched = true;
            this.targetIdx = i;
            break;
          }
        }
        if (matched) break;
      }
    }
    this.switchTo(this.targetIdx)
  }
  ,

  /**
   *
   */
  switchTo : function(idx) {
    var num = this.config.screens.length;
    while (idx<0) idx += num;
    idx = idx % num;
    var scrconfig = this.config.screens[idx];
    for (var i=0, len=this.config.screens.length; i<len; i++) {
      var cfg = this.config.screens[i];
      $('#screen-'+(i+1))[i == idx ? "show" : "hide"]();
    }
    this.targetIdx = idx;
    if (!scrconfig.rendered) {
      scrconfig.rendered = true;
      this.renderGadgets(scrconfig);
    }
  }
  ,

  /**
   *
   */
  renderGadgets : function(scrconfig) {
    var dashboard = this;
    var gadget;
    $.each(scrconfig.gadgets || [], function(i, gdconfig) {
      gadget = dashboard.addGadget(gdconfig);
    });
    if (gadget) gadget.focus();
  }
  ,

  /**
   *
   */
  currentScreen : function() {
    return this.el.find('#screen-'+(this.targetIdx+1));
  }
  ,

  /**
   *
   */
  addGadget : function(gdconfig, focus) {
    this.dirty(true);
    return new Gadget(gdconfig, this, focus);
  }
  ,

  /**
   *
   */
  refreshBackground : function() {
    var scrconfig = this.config.screens[this.targetIdx];
    this.currentScreen().find('> .wallpaper').css({
      backgroundColor : scrconfig.bgcolor || 'transparent',
      backgroundImage : scrconfig.bgimage ? 'url('+scrconfig.bgimage+')' : 'none',
      opacity : typeof scrconfig.opacity == 'number' ? scrconfig.opacity : 1
    })
  }
  ,

  /**
   *
   */
  persist : function() {
    var dashboard = this;
    var gadgets = [];
    this.currentScreen().find('.floating-gadget').each(function() {
      var gadget = $(this).data('gadget');
      gadgets.push([ $(this).css('zIndex'), gadget.config() ]);
    })
    gadgets = $.map(gadgets.sort(function(g1, g2) {
      var z1 = g1[0], z2 = g2[0];
      return z1 > z2 ? 1 : z1 < z2 ? -1 : 0;
    }), function(g) { return g[1] });
    dashboard.config.screens[this.targetIdx].gadgets = gadgets;
  }
  ,


  /**
   *
   */
  save : function() {
    this.persist();

    var dbconfig = $.extend({}, this.config);
    dbconfig.screens = $.map(dbconfig.screens, function(scrconfig) {
      scrconfig = $.extend({}, scrconfig);
      delete scrconfig.rendered;
      return scrconfig;
    });

    $.ajax({
      type: 'post',
      url: '/appdata/@viewer/@self',
      data: {
        dashboard : dbconfig
      },
      dataType: 'data'
    });

    this.dirty(false);
    return this;
  }
  ,

  /**
   *
   */
  dirty : function(dirty) { 
    if (typeof dirty !== 'undefined') {
      this._dirty = dirty; 
      return this;
    } else {
      return this._dirty;
    }
  }
  ,

  /**
   *
   */
  showSettingDialog : function() {
    new SettingDialog({ width : 400, height : 250, dashboard : this }).show();
  }

}


/**
 *
 *
 */
var Gadget = function(config, dashboard, focus) { 
  var gadget = this;
  this.initConfig = config;

  var id = 'floating-gadget-'+(Gadget.count++);
  gadget.el = $('<div class="floating-gadget" id="'+id+'"></div>')
    .append($('<div class="main" />')
      .addClass(config.color || '')
      .append('<div class="tl"><div class="tr"><div class="tc"></div></div></div>')
      .append('<div class="ml"><div class="mr"><div class="mc"></div></div></div>')
      .append('<div class="bl"><div class="br"><div class="bc"></div></div></div>'))
    .width(config.w || 250)
    .css({ 
      position : 'absolute',
      opacity : .1,
      zIndex : Gadget.zIndex++,
      left : typeof config.x == 'number' ?
             config.x : Math.floor((dashboard.el.width() - (config.w || 250)) / 2),
      top :  typeof config.y == 'number' ?
             config.y : Math.floor((dashboard.el.height() - (config.h || 150)) / 2)
    })
    .appendTo(dashboard.currentScreen())
    .draggable({ containment : '.dashboard' })
    .resizable({ 
      minWidth : 150,
      minHeight : 100,
      handles : 'se', 
      alsoResize : '#'+id+' .mc' 
    })
    .dblclick(function() {
      gadget.toggleGrow()
    })
    .mousedown(function() { 
      dashboard.dirty(true);
      gadget.focus(true);
    })
    .mouseup(function() {
      gadget.uncoverContent();
    })
    .bind('dragstart', function() { 
      gadget.coverContent();
    })
    .bind('dragstop', function() {
      gadget.uncoverContent();
    })
    .bind('dragstop', function() { dashboard.dirty(true) })
    .bind('resizestop', function() { 
      gadget.savedHeight = $(this).height();
      gadget.el.find('.mc iframe').height(gadget.el.find('.mc').height());
      dashboard.dirty(true);
    })
    .data('gadget', this)

  var mc = gadget.el.find('.mc');
  $('<div class="body"></div>')
    .appendTo(mc)
    .gadget(config.url, gadget.params());
  mc.mousedown(function(e) { e.stopPropagation() })
  if (typeof config.h == 'number') {
    setTimeout(function() { mc.find('iframe').height(mc.height()) }, 1000)
  }

  $(['<div class="pref">',
     '<table>',
     '<tr><td class="p">'+Gadget.LABEL_TITLE+'</td>',
     '    <td class="v title"><input type="text" name="title" /></td></tr>',
     '<tr><td class="p">'+Gadget.LABEL_COLOR+'</td>',
     '    <td class="v color"></td>',
     '</table>',
     '<div class="buttons">',
     '<input type="button" class="cancel" value="'+Gadget.LABEL_BUTTON_CANCEL+'" />',
     '<input type="button" class="ok" value="'+Gadget.LABEL_BUTTON_OK+'" />',
     '</div>',
     '</div>' ].join(''))
    .find('table tr td.color').each(function() {
      var td = $(this);
      $.each(Gadget.COLORS, function(i, c) {
        td.append(
          $('<span class="color" />')
            .data('color', c)
            .addClass(c)
            .addClass(config.color==c ? 'selected' : '')
            .click(function() {
              td.find('.color').each(function() {
                var sp = $(this);
                sp[sp.hasClass(c) ? 'addClass' : 'removeClass']('selected')
              })
            })
        )
      })
    }).end()
    /*
    .each(function() {
      var table = $(this);
      $.each(config.prefs || [], function(i, pref) {
        table.append($('<tr />')
          .append($('<td class="p">').text(pref.name))
          .append($('<td class="v">').append($('<input type="text" name="'+pref.name+'" pref.name)))
      })
    })
    */
    .find('.buttons > .cancel').click(function() {
      mc.children('.body, .pref').toggle();
    }).end()
    .find('.buttons > .ok').click(function() {
      gadget.savePreference();
      dashboard.dirty(true);
      mc.children('.body, .pref').toggle();
    }).end()
    .hide()
    .appendTo(mc)
    
  if (config.title) {
    $('<div class="header">')
      .appendTo(gadget.el.find('.tc'))
      .text(config.title)
  }
  if (typeof config.h == 'number') {
    gadget.height(config.h);
  }
  if (config.closable !== false) {
    $('<div class="btn-close-wrap" />')
      .append($('<div class="btn-close" />').hide())
      .mouseover(function() { $(this).children().show() })
      .mouseout(function() { $(this).children().hide() })
      .click(function() {
        dashboard.dirty(true);
        gadget.el.fadeOut('slow', function() { $(this).remove() });
      })
      .appendTo(gadget.el)
  }
  $('<div class="btn-pref-wrap" />')
    .append($('<div class="btn-pref" />').hide())
    .mouseover(function() { $(this).children().show() })
    .mouseout(function() { $(this).children().hide() })
    .click(function() {
      gadget.loadPreference();
      gadget.el.find('.mc').children('.body, .pref').toggle();
    })
    .appendTo(gadget.el)

  gadget.el.animate({ opacity : .9 }, { duration : 1000, complete : function() {
    if (focus) { gadget.focus() }
  }});
}

Gadget.count = 0;
Gadget.zIndex = 1000;

Gadget.COLORS = 'blue,cyan,green,yellow,red,magenta,gray,white'.split(',');
Gadget.LABEL_TITLE = 'Title';
Gadget.LABEL_COLOR = 'Color';
Gadget.LABEL_BUTTON_CANCEL = 'Cancel';
Gadget.LABEL_BUTTON_OK = 'OK';

Gadget.prototype = {
  /**
   *
   */
  skin : { CONTENT_BG_COLOR : '#ffffff' },

  /**
   *
   */
  loadPreference : function() {
    this.el.find('.pref')
      .find('td.title input').val(this.initConfig.title || '').end()
      .find('td.color span.color').removeClass('selected').end()
      .find('td.color span.'+(this.initConfig.color || 'blue')).addClass('selected');
  }
  ,

  /**
   *
   */
  savePreference : function() {
    var pref = this.el.find('.pref')
    var title = this.initConfig.title = pref.find('td.title input').val();
    var color = this.initConfig.color = pref.find('td.color span.selected').data('color');
    var main = this.el.find('> .main');
    $.each(Gadget.COLORS, function(i, c) {
      if (c !== color) main.removeClass(c);
      else main.addClass(c);
    });
    this.el.find('.header').text(title);
  }
  ,

  /**
   *
   */
  focus : function(cover) {
    var id = this.el.attr('id');
    $('.floating-gadget').each(function() {
      var gadget = $(this).data('gadget');
      if (gadget.el.attr('id')===id) {
        gadget.el.css({ opacity : 1, zIndex : Gadget.zIndex++ });
        if (!cover) gadget.uncoverContent();
      } else {
        gadget.el.css({ opacity : .8 });
        gadget.coverContent();
      }
    })
  }
  ,

  /**
   *
   */
  params : function() {
    var params = $.extend({ skin : this.skin }, environment );
    if (params.selectedText && params.selectedText.length>50) {
      params.selectedText = params.selectedText.substring(0, 50);
    }
    return params;
  }
  ,

  /**
   *
   */
  config : function() {
    var pos = this.el.position();
    var config = $.extend({}, this.initConfig);
    var h = this.el.css('height');
    if (h) {
      config.h = this.el.height();
    } else {
      delete config.h;
    }
    config = $.extend(config, {
      x : pos.left, y : pos.top,
      w : this.el.width()
    });
    return config;
  }
  ,

  /**
   *
   */
  height : function(height) {
    if (height==='auto') {
      this.el.find('.mc').width('auto').height('auto').end()
        .height('auto');
    } else if (typeof height=='number') {
      var diff = this.el.height() - height;
      var mc = this.el.find('.mc');
      mc.height(mc.height() - diff);
      this.el.height(height)
      this.savedHeight = height;
    }
  }
  ,

  /**
   *
   */
  toggleGrow : function() {
    if (typeof this.savedHeight == 'number') {
      var height = this.el.height();
      this.height(height == this.savedHeight ? 'auto' : this.savedHeight);
    } else {
      this.height('auto')
    }
  }
  ,

  /**
   *
   */
  coverContent : function() {
    var main = this.el.find('.main');
    main.prepend(
      $('<div class="cover" />')
        .width(main.width()).height(main.height())
        .html('&#160;')
    );
  }
  ,

  /**
   *
   */
  uncoverContent : function() {
    this.el.find('.cover').remove();
  }
  ,

  /**
   *
   */
  handleResize : function() {
  }
}

/**
 *
 */
var GadgetBar = function(gadgets, container) { 
  var gbar = this;
  gbar.gadgets = gadgets;

  gadgets = $.extend($.extend({}, GadgetBar.DEFAULT_GADGETS), gadgets);

  gbar.el = $('<div class="gadget-bar"></div>')
    .append(
      $('<div class="buttons closed"><div class="btn-toggle"></div></div>')
        .click(function() {
          $(this).toggleClass('closed')
            .find('> .btn-toggle').remove().end()
            .append('<div class="btn-toggle"></div>')
            .parent().find('> .main').slideToggle();
        })
    )
    .append(
      $('<div class="main"></div>')
        .append($('<div class="gadget-list"></div>'))
        .hide()
    )
    .appendTo(container)

  var gdlist = gbar.el.find('.gadget-list');

  gdlist
    .append(
      $('<div class="gadget new-gadget"></div>')
        .append($('<div class="title"></div>').text(GadgetBar.LABEL_LOAD_NEW_GADGET))
        .append($('<div class="icon"></div>'))
        .click(function() { gbar.showNewGadgetDialog() })
    )
    .append('<div class="separator"></div>')

  for (var url in gadgets) {
    var gdconfig = $.extend({ url : url }, gadgets[url]);
    this.addGadget(gdconfig);
  }

}

GadgetBar.LABEL_LOAD_NEW_GADGET = 'Add Gadget';
GadgetBar.DEFAULT_GADGETS = {
  'http://www.google.com/friendconnect/gadgets/members.xml' : {
    title : 'Member',
    thumbnail : 'http://www.google.com/friendconnect/scs/images/thumb/members.png'
  },
  'http://www.google.com/friendconnect/gadgets/wall.xml' : {
    title : 'Comment',
    thumbnail : 'http://www.google.com/friendconnect/scs/images/thumb/wall.png'
  }
};

GadgetBar.prototype = {
  /**
   *
   */
  registerDashboard : function(dashboard) {
    this.dashboard = dashboard;
  }
  ,

  /**
   *
   */
  showNewGadgetDialog : function() {
    var url = prompt('input new gadget URL', '')
    if (/^https?:\/\//.test(url)) {
      this.loadGadget(url);
    }
  }
  ,

  /**
   *
   */
  loadGadget : function(url) {
    var gbar = this;

    $.ajax({
      url : url,
      dataType : 'xml'
    }).next(function(doc) {
      var modulePref = doc.getElementsByTagName('ModulePrefs')[0]
      var gdconfig = gbar.gadgets[url] = { 
        title : modulePref.getAttribute('title'),
        description : modulePref.getAttribute('description'),
        thumbnail : modulePref.getAttribute('thumbnail'),
        userPrefs : getUserPrefs(doc)
      };
      gbar.addGadget($.extend({ url : url }, gdconfig));
      gbar.save();
    }).error(function() {
      //console.log(arguments);
    });

    function getUserPrefs(doc) {
      var ret = [];
      var userPrefs = doc.getElementsByTagName('UserPref');
      for (var i=0, len=userPrefs.length; i<len; i++) {
        var el = userPrefs[i];
        var userPref = {
          name : el.getAttribute('name'),
          displayName : el.getAttribute('display_name'),
          dataType : el.getAttribute('datatype'),
          required : el.getAttribute('required')==='true',
          defaultValue : el.getAttribute('default_value')
        }
        if (userPref.dataType=='enum') {
          userPref.enumValues = [];
          var enums = el.getElementsByTagName('EnumValue');
          for (var j=0; j<enums.length; j++) {
            userPref.enumValues.push({
              value : enums[j].getAttribute('value'),
              displayValue : enums[j].getAttribute('display_value')
            });
          }
        }
        ret.push(userPref);
      }
      return ret;
    }
  }
  ,

  /**
   *
   */
  addGadget : function(gdconfig) {
    var gbar = this;
    var gadget = $('<div class="gadget"></div>')
      .append($('<div class="title"></div>').text(gdconfig.title))
      .append($('<div class="icon"></div>'))
      .data('config', gdconfig)
      .insertBefore('.gadget-list .new-gadget')
      .click(function() { gbar.dashboard.addGadget($(this).data('config'), true) })
    if (gdconfig.thumbnail) {
      gadget.find('.icon').append($('<img />').attr('src', gdconfig.thumbnail))
    } else {
      gadget.addClass('default');
    }
    return this;
  }
  ,

  /**
   *
   */
  save : function() {
    $.ajax({
      type: 'post',
      url: '/appdata/@viewer/@self',
      data: {
        gadgets : this.gadgets
      },
      dataType: 'data'
    });
    return this;
  }

}


/**
 *
 */
var Dialog = function(config) {
  this.config = config || {};
} 

Dialog.prototype = {
  /**
   *
   */
  show : function() {
    var dialog = this;
    var body = $(document.body);
    var docW = $(document).width(), docH = $(document).height();
    this.mask = $('<div class="dialog-mask" />')
      .width(docW).height(docH)
      .appendTo(body)
    var w = this.config.width || 400;
    var h = this.config.height || 300;
    this.el = $('<div class="dialog-content" />')
      .width(w).height(h)
      .css({ left : Math.floor((docW - w) *.5) + 'px', 
             top : Math.floor((docH - h) * .5) + 'px' })
      .appendTo(body)

    this.render();
  }
  ,

  /**
   *
   */
  close : function() {
    if (this.mask) this.mask.remove();
    if (this.el) this.el.remove();
  }

}

/**
 *
 */
var SettingDialog = extend(Dialog, {
  /**
   *
   */
  init : function(config) {
    this.dashboard = config.dashboard;
  }
  ,

  /**
   *
   */
  render : function() {
    var dialog = this;

    this.el.append([
      '<div class="body">',
      ' <h1>'+SettingDialog.LABEL_DASHBOARD_PROPS+'</h1>',
      ' <div class="prompt">',
      '   <span class="label">'+SettingDialog.LABEL_BGCOLOR+':</span>',
      '   <input style="width:60px" name="bgcolor" type="text" maxlength="7" />',
      ' </div>',
      ' <div class="prompt">',
      '   <span class="label">'+SettingDialog.LABEL_BG_IMAGE_URL+':</span><br/>',
      '   <input class="url" name="bgimage" type="text" />',
      ' </div>',
      ' <div class="prompt">',
      '   <span class="label">'+SettingDialog.LABEL_OPACITY+':</span>',
      '   <input style="width:30px" name="opacity" type="text" maxlength="6" />',
      ' </div>',
      ' <div class="prompt">',
      '   <span class="label">'+SettingDialog.LABEL_URL_PATTERN+':</span><br/>',
      '   <input class="url" name="urlpattern" type="text" />',
      ' </div>',
      '</div>'
    ].join(''))
    .append([
      '<div class="buttons">',
      '  <input type="button" name="cancel" value="'+SettingDialog.LABEL_BUTTON_CANCEL+'" />',
      '  <input type="button" name="ok" value="'+SettingDialog.LABEL_BUTTON_OK+'" />',
      '</div>'
    ].join(''))
    .find('.buttons')
      .children('input[name="cancel"]').click(function() {
        dialog.close();
      }).end()
      .children('input[name="ok"]').click(function() {
        dialog.save();
      })
    .end()

    var scrconfig = this.dashboard.config.screens[this.dashboard.targetIdx];
    var body = this.el.find('.body');
    body.find('input[name="bgcolor"]').val(scrconfig.bgcolor);
    body.find('input[name="bgimage"]').val(scrconfig.bgimage);
    body.find('input[name="opacity"]').val(scrconfig.opacity ? Math.floor(scrconfig.opacity * 100) : '');
    body.find('input[name="urlpattern"]').val(scrconfig.urlpattern);
  }
  ,

  /**
   *
   */
  save : function() {
    var body = this.el.find('.body');
    var bgcolor = body.find('input[name="bgcolor"]').val();
    if (bgcolor && !/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(bgcolor)) {
      alert(SettingDialog.MESSAGE_BGCOLOR_FORMAT);
      return;
    }
    var bgimage = body.find('input[name="bgimage"]').val();
    if (bgimage && !/^https?:\/\//.test(bgimage)) {
      alert(SettingDialog.MESSAGE_BGIMAGE_FORMAT);
      return;
    }
    var opacity = body.find('input[name="opacity"]').val();
    if (opacity) {
      opacity = parseInt(opacity, 10);
      if (opacity<0 || opacity > 100) {
        alert(SettingDialog.MESSAGE_OPACITY_FORMAT);
        return;
      }
    }
    var urlpattern = body.find('input[name="urlpattern"]').val();
    if (urlpattern && !/^https?:\/\//.test(urlpattern)) {
      alert(SettingDialog.MESSAGE_URLPATTERN_FORMAT);
      return;
    }

    var scrconfig = this.dashboard.config.screens[this.dashboard.targetIdx];
    if (bgcolor) scrconfig.bgcolor = bgcolor; else delete scrconfig.bgcolor;
    if (bgimage) scrconfig.bgimage = bgimage; else delete scrconfig.bgimage;
    if (opacity) scrconfig.opacity = opacity/100; else delete scrconfig.opacity;
    if (urlpattern) scrconfig.urlpattern = urlpattern; else delete scrconfig.urlpattern;

    this.dashboard.save();

    if (bgcolor || bgimage || opacity) {
      this.dashboard.refreshBackground();
    }

    this.close();
  }

});

SettingDialog.LABEL_DASHBOARD_PROPS = 'Dashboard Setting';
SettingDialog.LABEL_BGCOLOR = 'Background Color';
SettingDialog.LABEL_BG_IMAGE_URL = 'Background Image URL';
SettingDialog.LABEL_OPACITY = 'Background Opacity (0 - 100)';
SettingDialog.LABEL_URL_PATTERN = 
  'URL Pattern (for bookmarklet; "*" is wildcard)';
SettingDialog.LABEL_BUTTON_CANCEL = 'Cancel';
SettingDialog.LABEL_BUTTON_OK = 'OK';
SettingDialog.MESSAGE_BGCOLOR_FORMAT = 'Background Color format should be #fff or #ffffff';
SettingDialog.MESSAGE_BGIMAGE_FORMAT = 'Background Image URL is not valid';
SettingDialog.MESSAGE_OPACITY_FORMAT = 'Background Opacity should be number from 0 to 100';
SettingDialog.MESSAGE_URLPATTERN_FORMAT = 'URL Pattern is not valid';



/**
 *
 */
var plugins = [];
var environment = {};
var preferences = {};

/**
 *
 */
return {

  Dashboard : Dashboard,
  Gadget : Gadget,
  GadgetBar : GadgetBar,
  Dialog : Dialog,
  SettingDialog : SettingDialog,

  /**
   *
   */
  DEFAULT_DASHBOARD : {
    screens : [{
      name : 'default',
      bgcolor : '#667788',
      opacity : .5
    }, {
      name : 'work',
      bgcolor : '#aaffaa',
      opacity : .5
    }, {
      name : 'hobby',
      bgcolor : '#ffaaff',
      opacity : .5
    }]
  }
  ,

  /**
   *
   */
  registerPlugin : function(plugin) {
    plugins.push(plugin);
  }
  ,

  /**
   *
   */
  init : function() {
    var overlay = location.href.split('#').pop()=='overlay';
    document.body.className = overlay ? 'overlay' : 'standalone';
    environment = $.extend(environment, window.name ? gadgets.json.parse(window.name) : {});
    SocialDashboard.initPlugins();
  }
  ,

  /**
   *
   */
  initPlugins : function() {
    var count = 0;
    if (plugins.length>0) {
      $.each(plugins, function(i, plugin) {
        plugin.execute(environment, next, next)
      })
    } else {
      SocialDashboard.loadConfig();
    }
    function next() { 
      count++; 
      if (count==plugins.length) SocialDashboard.loadConfig();
    }
  }
  ,

  /**
   *
   */
  loadConfig : function() {
    $.ajax({ 
      url : '/appdata/@viewer/@self',
      dataType : 'data'
    })
    .next(function(data) {
      var config;
      for (var vid in data) {
        config = data[vid];
        break;
      }
      if (!config) {
        config = {
          dashboard : deepCopy(SocialDashboard.DEFAULT_DASHBOARD)
        }
      }
      SocialDashboard.render(config);
    })
    .error(function(error) {
      var config = {
        dashboard : deepCopy(SocialDashboard.DEFAULT_DASHBOARD)
      }
      SocialDashboard.render(config);
    });
  }
  ,

  /**
   *
   */
  render : function(config) {
    $(document.body).children('.gadget-bar, .dashboard').remove();

    if (!config.dashboard) {
      config.dashboad = deepCopy(SocialDashboard.DEFAULT_DASHBOARD);
    }
    if (!config.dashboard.screens) {
      var screen = $.extend({}, SocialDashboard.DEFAULT_DASHBOARD.screens[0] || {});
      delete screen.gadgets;
      screen = $.extend(config.dashboard, screen);
      config.dashboard = {
        screens : [ screen ].concat(
          SocialDashboard.DEFAULT_DASHBOARD.screens.slice(1))
      }
    }
    var gbar = new GadgetBar(config.gadgets || [], document.body);
    var dashboard = new Dashboard(config.dashboard, document.body);
    gbar.registerDashboard(dashboard);

    // auto saving in 10 sec if dirty...
    setInterval(function() {
      if (dashboard.dirty()) dashboard.save();
    }, 10000);
  }
  ,

  /**
   *
   */
  refresh : function() {
    $(document.body).children('.gadget-bar, .dashboard').remove();
    this.loadConfig();
  }
  ,


  /**
   *
   */
  resetConfig : function(keys) {
    keys = keys || ['dashboard','dashboards','gadgets'];
    var req = opensocial.newDataRequest();
    req.add(req.newRemovePersonAppDataRequest(
      opensocial.IdSpec.PersonId.VIEWER, keys), "response")
    req.send(function() {})
  }
  ,

  /**
   *
   */
  gadgetUrl : function(name) {
    return this.dashboardBaseUrl() + '/gadgets/' + name + '.xml?';
  }
  ,

  /**
   *
   */
  dashboardBaseUrl : function() {
    if (this._dashboardBaseUrl) return this._dashboardBaseUrl;

    var scripts = document.getElementsByTagName('script');
    var src = scripts[scripts.length-1].src;
    if (!/^https?:\/\//.test(src)) { // ie returns relative path
      if (src.indexOf('/')==0) {
        src = location.href.split('/').slice(0, 3).join('/') + src;
      } else {
        src = location.href.split('/').slice(0, -1).join('/') + '/' + src;
      }
    }
    return this._dashboardBaseUrl = src.split('/').slice(0, -2).join('/');
  }
  ,

  /**
   *
   */
  fixpng : window.ActiveXObject ? // IE
    function(el) {
      var src = el.currentStyle.getAttribute("backgroundImage").slice(5,-2);
      el.style.backgroundImage = 'url('+src.replace(/png$/, 'gif')+')';
      el.style.behavior = "none";
    } : function() {}
  
}

}
